Connection Syntax (Advanced)
Users can override the automatic connection signatures by specifying repeat counts; by changing the dimensions or by specifying which object elements connect to which. To this end Blueprint provides a Connection Dialog that allows users to specify their own loops, switches and connections using the full connection Syntax
The advanced connection syntax extends the basic syntax to include the user specified loops and selections
Adv Signature:
{Basic Signature} | {Loop} | {Switch}
Loop:
{Dim} [ . {Loop}]
Switch:
< {Switch index} > { {Switch Signature} [{Switch Signature}] }
Switch Index:
{Connectee Index} | {Connector Index}
Switch Signature:
{Case Selector}{Adv Signature}
Case Selector:
< [{Max Value}] [ , {Min Value}] >
Min Value:
Max Value:
{Value}
Eg. K<#0>{<2,1>[0]<4,3>L[1]} with 'Repeat count' R
for each element of connector object
for 1..K
switch #0
case 1..2:
for repeat count R
ConnectTo( 0 )
case 3..4:
for 1..L
for repeat count R
ConnectTo( 1 )
Irregular Connections
In some cases an even more advanced connection logic is required that cannot be defined by simple loops and switches. To this end Blueprint allows irregular connections to be defined via user defined macro functions.
In the following examples the an array of consumer objects only requires connections to a sub set of the provider objects (both same dimension). The first is a 1-d example, the second a 2-d example.
Example 1
The 1-d Collector is required to make a sub set of connections to the semaphore, depending on its element number.
Each collector element 'n' connects to a pair of Counting Semaphores 'n' and 'n+1'. However, if 'n' is odd it must connect to element 'n' then 'n+1', if even it must connect in the opposite order 'n+1' then 'n'. When 'n+1' is greater then the number of elements, it must wrap around to element 0.
If NP is known then this connection 'could' be configured using the switch mechanism, but this could be cumbersome and prone to errors, especially if NP was to be changed. To make this connection using macros we need to generate two macro functions 'First()', 'Second()', and make connections using these.
These functions can be defined in the ProjectHeader.hpp file. Each function generates a single element number.
#define NP 7
#define First( X ) ( ((X)%2) ? (X) : (((X)+1)%NP) ) // if odd connect to X else X+1 - wrap X+1 to 0 if required
#define Second( X ) ( ((X)%2) ? (((X)+1)%NP) : (X) ) // if odd connect to X+1 else X - wrap X+1 to 0 if required
In this example the arguments to the macros are simply the loop variable, but this not a restriction. We could have passed other parameters into the macro
Eg.
#define Next( N, X, Y ) ( ((N)==1) ? ( ((X)%2) ? (X) : ( ((X)+1) % (Y) ) ) : ( ((X)%2) ? ( ((X)+1) % (Y) ) : (X) ) )
ConnectTo( Next( 1, #0, NP ) )
ConnectTo( Next( 2, #0+1, NP/2 )
Example 2
In this 2-d grid example each collector needs to make a sub set of connections the the data store depending on the its element number.
Each collector n,m connects to its 8 neighbours and itself (in a specific order).
The connections also need to wrap around at the each edges/corners of the grid.
To configure this connection using switches and cases would be extremely arduous and only possible if N and M where known (and small).
We can make this connection using macros. To do this we need to generate macro functions with the following formats (since it must generate 2 values and used to initialise a array of constants)
#define G( X ) something // NB. G and H could be the same
#define H( Y ) something
#define F( X, Y ) G( X ), H( Y ) // NB. no outer brackets around the G,H functions
generated code
const Uns elem[2] = { F( e1, e0 ) };
which after macro substitution is equivalent to
const Uns elem[2] = { G( e1 ), H( e0 ) };
Thus for this example we would define the macros (in ProjectHeader.hpp)
#define N 10
#define M 10
#define Wrap( Xi, X ) ( ((X)+(Xi)) % (X) )
#define Wrap2( Ni, Mi ) Wrap( (Ni), (N) ), Wrap( (Mi), (M) )
Using the connection dialog the to create these nine connections would have generated a connection dimension of [9]. In this example, this is is not particularly useful, so using the connection dialog we can overwrite the dimension to [3][3]. However, there are a number of restrictions that must be observed with redimensioning connections.
Connection Dimensions
If the user overrides the connection dimension, this new dimension is validated against the calculated dimension. Warnings are generated if there is a mismatch that is plausible (highlights the fact that it has been changed), whilst errors are generated if there is an implausible or dangerous mismatch.
Eg.
Calculated Dimension User Specified Dimension Condition Comments
[9] [3][3] Warning Splitting a dimension is allowable
[3][3] [9] Warning Combining a dimension is allowable
[4][3] [2][6] Error Splitting one dimension and combining with another is not recommended
[2][9][4] [9][8] Error Combining (or splitting) non-adjacent dimensions is not recommended
[10] [3][3] Error Dimension mismatch
[N] [2] Error Dimension mismatch
[3][4][2] [4][3][2] Error Dimension reordering is not recommended
[N][2] [N*2] Error Can only combine (or split) numeric dimensions
There are a number of conditions where it is not possible to calculate a connection dimension from a signature. This usually occurs when there are different connection structures within switch cases, or flat loops (as opposed to nested loops) with different loop sizes or internal structures.
Eg
switch
case 1
connect to element 1;
case 2
connect to elements 1 and 2;
...
case N
for X in 1..N
connect to element X
In this instance there are different dimensions for each case (1, 2, N).
When a dimension cannot be calculated, a dimension of [*] will be used by the Translator to generate an access function with 1 argument (plus any repeat count argument) and thus it is up to the user to decode the connection structure to get to the actual connection element number.
NB: The access functions generated from [*] connections will not check do any dimension bounds checking.
If the user overrides a [*] dimension it is assumed the user knows best and thus the user specified dimension will be used by the translator.